/*
 * PhotonRTOS础光实时操作系统 -- 位图头文件
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef PHOTON_BITMAP_H
#define PHOTON_BITMAP_H

#ifndef __ASSEMBLY__

#include <photon/types.h>
#include <photon/kernel.h>
#include <photon/bitops.h>
#include <photon/string.h>

extern int32_t __bitmap_empty(const uintptr_t *bitmap, int32_t bits);
extern int32_t __bitmap_full(const uintptr_t *bitmap, int32_t bits);
extern int32_t __bitmap_equal(const uintptr_t *bitmap1,
		const	uintptr_t *bitmap2, int32_t bits);
extern void __bitmap_complement(uintptr_t *dst, const uintptr_t *src,
			int32_t bits);
extern void __bitmap_shift_right(uintptr_t *dst,
		const	uintptr_t *src, int32_t shift, int32_t bits);
extern void __bitmap_shift_left(uintptr_t *dst,
		const	uintptr_t *src, int32_t shift, int32_t bits);
extern int32_t __bitmap_and(uintptr_t *dst, const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern void __bitmap_or(uintptr_t *dst, const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern void __bitmap_xor(uintptr_t *dst, const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern int32_t __bitmap_andnot(uintptr_t *dst, const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern int32_t __bitmap_intersects(const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern int32_t __bitmap_subset(const uintptr_t *bitmap1,
			const uintptr_t *bitmap2, int32_t bits);
extern int32_t __bitmap_weight(const uintptr_t *bitmap, int32_t bits);

extern void bitmap_set(uintptr_t *map, int32_t i, int32_t len);
extern void bitmap_clear(uintptr_t *map, int32_t start, int32_t nr);
extern uintptr_t bitmap_find_next_zero_area(uintptr_t *map,
					 uintptr_t size,
					 uintptr_t start,
					 uint32_t nr,
					 uintptr_t align_mask);

extern int32_t bitmap_scnprintf(int8_t *buf, uint32_t len,
			const uintptr_t *src, int32_t nbits);
extern int32_t __bitmap_parse(const int8_t *buf, uint32_t buflen, int32_t is_user,
			uintptr_t *dst, int32_t nbits);
extern int32_t bitmap_parse_user(const int8_t *ubuf, uint32_t ulen,
			uintptr_t *dst, int32_t nbits);
extern int32_t bitmap_scnlistprintf(int8_t *buf, uint32_t len,
			const uintptr_t *src, int32_t nbits);
extern int32_t bitmap_parselist(const int8_t *buf, uintptr_t *maskp,
			int32_t nmaskbits);
extern void bitmap_remap(uintptr_t *dst, const uintptr_t *src,
		const uintptr_t *old, const uintptr_t *new, int32_t bits);
extern int32_t bitmap_bitremap(int32_t oldbit,
		const uintptr_t *old, const uintptr_t *new, int32_t bits);
extern void bitmap_onto(uintptr_t *dst, const uintptr_t *orig,
		const uintptr_t *relmap, int32_t bits);
extern void bitmap_fold(uintptr_t *dst, const uintptr_t *orig,
		int32_t sz, int32_t bits);
extern int32_t bitmap_find_free_region(uintptr_t *bitmap, int32_t bits, int32_t order);
extern void bitmap_release_region(uintptr_t *bitmap, int32_t pos, int32_t order);
extern int32_t bitmap_allocate_region(uintptr_t *bitmap, int32_t pos, int32_t order);
extern void bitmap_copy_le(void *dst, const uintptr_t *src, int32_t nbits);

#define BITMAP_LAST_WORD_MASK(nbits)					\
(									\
	((nbits) % BITS_PER_LONG) ?					\
		(1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL		\
)

#define small_const_nbits(nbits) \
	(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)

static inline void bitmap_zero(uintptr_t *dst, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = 0UL;
	}
	else {
		int32_t len = BITS_TO_LONGS(nbits) * sizeof(uintptr_t);

		memset(dst, 0, len);
	}
}

static inline void bitmap_fill(uintptr_t *dst, int32_t nbits)
{
	size_t nlongs = BITS_TO_LONGS(nbits);

	if (!small_const_nbits(nbits)) {
		int32_t len = (nlongs - 1) * sizeof(uintptr_t);

		memset(dst, 0xff,  len);
	}
	dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
}

static inline void bitmap_copy(uintptr_t *dst, const uintptr_t *src,
			int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = *src;
	}
	else {
		int32_t len = BITS_TO_LONGS(nbits) * sizeof(uintptr_t);

		memcpy(dst, src, len);
	}
}

static inline int32_t bitmap_and(uintptr_t *dst, const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return (*dst = *src1 & *src2) != 0;
	}
	return __bitmap_and(dst, src1, src2, nbits);
}

static inline void bitmap_or(uintptr_t *dst, const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = *src1 | *src2;
	} else {
		__bitmap_or(dst, src1, src2, nbits);
	}
}

static inline void bitmap_xor(uintptr_t *dst, const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = *src1 ^ *src2;
	} else {
		__bitmap_xor(dst, src1, src2, nbits);
	}
}

static inline int32_t bitmap_andnot(uintptr_t *dst, const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return (*dst = *src1 & ~(*src2)) != 0;
	}
	return __bitmap_andnot(dst, src1, src2, nbits);
}

static inline void bitmap_complement(uintptr_t *dst,
		const uintptr_t *src, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
	} else {
		__bitmap_complement(dst, src, nbits);
	}
}

static inline int32_t bitmap_equal(const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
	} else {
		return __bitmap_equal(src1, src2, nbits);
	}
}

static inline int32_t bitmap_intersects(const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
	} else {
		return __bitmap_intersects(src1, src2, nbits);
	}
}

static inline int32_t bitmap_subset(const uintptr_t *src1,
			const uintptr_t *src2, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return !((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
	} else {
		return __bitmap_subset(src1, src2, nbits);
	}
}

static inline int32_t bitmap_empty(const uintptr_t *src, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return !(*src & BITMAP_LAST_WORD_MASK(nbits));
	} else {
		return __bitmap_empty(src, nbits);
	}
}

static inline int32_t bitmap_full(const uintptr_t *src, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		return !(~(*src) & BITMAP_LAST_WORD_MASK(nbits));
	} else {
		return __bitmap_full(src, nbits);
	}
}

static inline int32_t bitmap_weight(const uintptr_t *src, int32_t nbits)
{
#if 0
	if (small_const_nbits(nbits)) {
		return hweight_intptr_t(*src & BITMAP_LAST_WORD_MASK(nbits));
	}
#endif
	return __bitmap_weight(src, nbits);
}

static inline void bitmap_shift_right(uintptr_t *dst,
			const uintptr_t *src, int32_t n, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = *src >> n;
	} else {
		__bitmap_shift_right(dst, src, n, nbits);
	}
}

static inline void bitmap_shift_left(uintptr_t *dst,
			const uintptr_t *src, int32_t n, int32_t nbits)
{
	if (small_const_nbits(nbits)) {
		*dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits);
	} else {
		__bitmap_shift_left(dst, src, n, nbits);
	}
}

static inline int32_t bitmap_parse(const int8_t *buf, uint32_t buflen,
			uintptr_t *maskp, int32_t nmaskbits)
{
	return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
}

#endif /* __ASSEMBLY__ */

#endif /* PHOTON_BITMAP_H */
